<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 6.0.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/wang-cheng/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/wang-cheng/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/wang-cheng/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/wang-cheng/images/logo.svg" color="#222">

<link rel="stylesheet" href="/wang-cheng/css/main.css">


<link rel="stylesheet" href="/wang-cheng/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"cheng-wang123.gitee.io","root":"/wang-cheng/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":false,"scrollpercent":false},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":false,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}}};
  </script>

  <meta name="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
<meta property="og:type" content="website">
<meta property="og:title" content="诚の博客">
<meta property="og:url" content="https://cheng-wang123.gitee.io/wang-cheng/page/4/index.html">
<meta property="og:site_name" content="诚の博客">
<meta property="og:description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
<meta property="og:locale" content="zh_CN">
<meta property="article:author" content="王诚">
<meta name="twitter:card" content="summary">

<link rel="canonical" href="https://cheng-wang123.gitee.io/wang-cheng/page/4/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : true,
    isPost : false,
    lang   : 'zh-CN'
  };
</script>

  <title>诚の博客</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

<link rel="alternate" href="/wang-cheng/atom.xml" title="诚の博客" type="application/atom+xml">
</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/wang-cheng/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">诚の博客</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">记录学习中的点点滴滴</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/wang-cheng/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/wang-cheng/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/wang-cheng/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/wang-cheng/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
  </ul>
</nav>




</div>
    </header>

    
  <div class="back-to-top">
    <i class="fa fa-arrow-up"></i>
    <span>0%</span>
  </div>


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content index posts-expand">
            
      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/04/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/04/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/" class="post-title-link" itemprop="url">动态代理</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-04 14:44:28" itemprop="dateCreated datePublished" datetime="2022-03-04T14:44:28+08:00">2022-03-04</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-03-06 18:59:46" itemprop="dateModified" datetime="2022-03-06T18:59:46+08:00">2022-03-06</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="动态代理"><a href="#动态代理" class="headerlink" title="动态代理"></a><strong>动态代理</strong></h1><h2 id="什么是代理"><a href="#什么是代理" class="headerlink" title="什么是代理"></a><strong>什么是代理</strong></h2><p>代理是一种常用的设计模式，其目的就是为其他对象提供一个代理以控制对某个对象的访问。代理类负责为委托类预处理消息，过滤消息并转发消息，以及进行消息被委托类执行后的后续处理</p>
<img src="/wang-cheng/2022/03/04/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86_UML.jpg" class title="动态代理_UML">

<p>代理又分为动态代理和静态代理两种，这里主要记录动态代理。</p>
<p><strong>正常类创建对象的过程:</strong></p>
<img src="/wang-cheng/2022/03/04/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/%E6%AD%A3%E5%B8%B8%E7%B1%BB%E5%88%9B%E5%BB%BA%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%BF%87%E7%A8%8B.jpg" class title="正常类创建对象的过程">
<p><strong>动态代理创建代理对象的过程:</strong></p>
<img src="/wang-cheng/2022/03/04/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86/%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86%E5%88%9B%E5%BB%BA%E4%BB%A3%E7%90%86%E5%AF%B9%E8%B1%A1%E7%9A%84%E8%BF%87%E7%A8%8B.jpg" class title="动态代理创建代理对象的过程">

<p>而动态代理目前常用的有JDK的动态代理和CGLib的动态代理，下面分别记录。</p>
<h2 id="JDK动态代理"><a href="#JDK动态代理" class="headerlink" title="JDK动态代理"></a><strong>JDK动态代理</strong></h2><p><strong>基于接口的动态代理</strong></p>
<p><strong>提供者:JDK</strong></p>
<p><strong>使用官方的<code>Proxy</code>类创建代理对象</strong></p>
<p>使用JDK动态代理，代理对象必须要有实现类。</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">interface</span> <span class="title class_">TargetInterface</span> &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title class_">String</span> <span class="title function_">sayHello</span>(<span class="title class_">String</span> name);</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title class_">String</span> <span class="title function_">sayThanks</span>(<span class="title class_">String</span> name);</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TargetInterfaceImpl</span> <span class="keyword">implements</span> <span class="title class_">TargetInterface</span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="title class_">String</span> <span class="title function_">sayHello</span>(<span class="params"><span class="built_in">String</span> name</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;hello,&quot;</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">public</span> <span class="title class_">String</span> <span class="title function_">sayThanks</span>(<span class="params"><span class="built_in">String</span> name</span>) &#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="string">&quot;Thanks,&quot;</span> + name;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TargetProxy</span> <span class="keyword">implements</span> <span class="title class_">InvocationHandler</span> &#123;</span><br><span class="line">    <span class="comment">/**</span></span><br><span class="line"><span class="comment">     * 持有目标类的接口类的引用</span></span><br><span class="line"><span class="comment">     */</span></span><br><span class="line">    <span class="keyword">private</span> <span class="title class_">Object</span> target;</span><br><span class="line">    <span class="comment">//构造方法对其进行初始化</span></span><br><span class="line">    <span class="keyword">public</span> <span class="title class_">TargetProxy</span>(<span class="title class_">Object</span> target) &#123;</span><br><span class="line">        <span class="variable language_">this</span>.<span class="property">target</span> = target;</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="comment">//获取真正的代理类</span></span><br><span class="line">    <span class="meta">@SuppressWarnings</span>(<span class="string">&quot;unchecked&quot;</span>)</span><br><span class="line">    <span class="keyword">public</span> &lt;T&gt; T <span class="title function_">getProxy</span>(<span class="params">Class clazz</span>)&#123;</span><br><span class="line">        <span class="comment">/**</span></span><br><span class="line"><span class="comment">         * public static Object newProxyInstance(ClassLoader loader,Class&lt;?&gt;[] interfaces,InvocationHandler h)</span></span><br><span class="line"><span class="comment">         */</span></span><br><span class="line">        <span class="keyword">return</span> (T)<span class="title class_">Proxy</span>.<span class="title function_">newProxyInstance</span>(target.<span class="title function_">getClass</span>().<span class="title function_">getClassLoader</span>(),<span class="title class_">TargetInterfaceImpl</span>.<span class="property">class</span>.<span class="title function_">getInterfaces</span>(),<span class="variable language_">this</span>);</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title class_">Object</span> <span class="title function_">invoke</span>(<span class="title class_">Object</span> proxy, <span class="title class_">Method</span> method, <span class="title class_">Object</span>[] args) throws <span class="title class_">Throwable</span> &#123;</span><br><span class="line">        <span class="title class_">System</span>.<span class="property">out</span>.<span class="title function_">println</span>(<span class="string">&quot;数据缓存............&quot;</span>);</span><br><span class="line">        <span class="comment">//调目标方法</span></span><br><span class="line">        <span class="keyword">return</span> method.<span class="title function_">invoke</span>(target,args);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="title function_">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>) &#123;</span><br><span class="line">        <span class="title class_">TargetProxy</span> targetProxy = <span class="keyword">new</span> <span class="title class_">TargetProxy</span>(<span class="keyword">new</span> <span class="title class_">TargetInterfaceImpl</span>());</span><br><span class="line">        <span class="title class_">TargetInterface</span> proxy = targetProxy.<span class="title function_">getProxy</span>(<span class="title class_">TargetInterface</span>.<span class="property">class</span>);</span><br><span class="line">        <span class="title class_">System</span>.<span class="property">out</span>.<span class="title function_">println</span>(proxy.<span class="title function_">sayHello</span>(<span class="string">&quot;zhangsan&quot;</span>));</span><br><span class="line">        <span class="title class_">System</span>.<span class="property">out</span>.<span class="title function_">println</span>(proxy.<span class="title function_">sayThanks</span>(<span class="string">&quot;李四&quot;</span>));</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>首先要代理的对象必须实现一个接口，这个条件是必不可少的。</p>
<p>然后，我们用一个<code>InvocationHandler</code>的实现类，去实现要代理的功能。</p>
<p><code>InvocationHandler</code>接口中只有一个方法<code>invoke(Object proxy, Method method, Object[] args)</code>。该方法就是我们要调用的方法，在该方法前或后实现的功能就是我们要代理的功能。</p>
<p>而我们要得到这个代理类，就需要用到<code>Proxy</code>类的<code>newProxyInstance(ClassLoader loader,Class&lt;?&gt;[] interfaces,InvocationHandler h)</code>方法。该方法将返回一个代理对象，我们拿到这个代理对象去调用我们要代理的方法。其中的参数分别为指定一个类加载器(一般用代理对象)、一组接口(代理对象实现的接口)、处理器。</p>
<p>上述代码中，TargetProxy类的getProxy()方法用于生成并返回一个代理对象，在该方法中调用了Proxy的newProxyInstance()方法并将生成的对象返回。</p>
<hr>
<p><strong>JDK动态代理只能对实现了接口的类生成代理，而不能针对类，具有一定的局限性</strong></p>
<p><strong>JDK动态代理利用的是反射机制(而关于反射的原理，等以后详细学习后再专门来写)</strong></p>
<h2 id="CGLib动态代理"><a href="#CGLib动态代理" class="headerlink" title="CGLib动态代理"></a><strong>CGLib动态代理</strong></h2><p>CGLIB动态代理的代理对象非常广泛，一般只要方法没有用final修饰或类被final修饰的，都可以被代理。CGLib采用了非常底层的字节码技术，其原理是通过字节码技术为一个类创建子类，在子类中采用方法拦截的技术拦截所有父类方法的调用。</p>
<figure class="highlight typescript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">UserService</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="built_in">void</span> <span class="title function_">thinking</span>(<span class="params"></span>)&#123;</span><br><span class="line">        <span class="title class_">System</span>.<span class="property">out</span>.<span class="title function_">println</span>(<span class="string">&quot;I&#x27;m thinking&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">TargetProxy</span> <span class="keyword">implements</span> <span class="title class_">MethodInterceptor</span> &#123;</span><br><span class="line">    <span class="comment">//获取真正的代理类</span></span><br><span class="line">    <span class="keyword">public</span> &lt;T&gt; T <span class="title function_">getProxy</span>(<span class="params">Class clazz</span>)&#123;<span class="comment">//2</span></span><br><span class="line">        <span class="comment">//字节码增强的一个类</span></span><br><span class="line">        <span class="title class_">Enhancer</span> enhancer = <span class="keyword">new</span> <span class="title class_">Enhancer</span>();</span><br><span class="line">        <span class="comment">//设置父类</span></span><br><span class="line">        enhancer.<span class="title function_">setSuperclass</span>(clazz);</span><br><span class="line">        <span class="comment">//设置回调类</span></span><br><span class="line">        enhancer.<span class="title function_">setCallback</span>(<span class="variable language_">this</span>);</span><br><span class="line">        <span class="comment">//创建代理类</span></span><br><span class="line">        <span class="keyword">return</span> (T) enhancer.<span class="title function_">create</span>();</span><br><span class="line">    &#125;</span><br><span class="line">    <span class="keyword">public</span> <span class="title class_">Object</span> <span class="title function_">intercept</span>(<span class="title class_">Object</span> o, <span class="title class_">Method</span> method, <span class="title class_">Object</span>[] objects, <span class="title class_">MethodProxy</span> <span class="title class_">Proxy</span>) throws <span class="title class_">Throwable</span> &#123;<span class="comment">//3</span></span><br><span class="line">        <span class="title class_">System</span>.<span class="property">out</span>.<span class="title function_">println</span>(<span class="string">&quot;服务限流............&quot;</span>);</span><br><span class="line">        <span class="comment">//调用目标方法</span></span><br><span class="line">        <span class="keyword">return</span> <span class="title class_">Proxy</span>.<span class="title function_">invokeSuper</span>(o,objects);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"><span class="keyword">public</span> <span class="keyword">class</span> <span class="title class_">Test</span> &#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="built_in">void</span> <span class="title function_">main</span>(<span class="params"><span class="built_in">String</span>[] args</span>) &#123;</span><br><span class="line">        <span class="title class_">TargetProxy</span> targetProxy = <span class="keyword">new</span> <span class="title class_">TargetProxy</span>();</span><br><span class="line">        <span class="comment">//拿到目标类的代理类</span></span><br><span class="line">        <span class="title class_">UserService</span> service = targetProxy.<span class="title function_">getProxy</span>(<span class="title class_">UserService</span>.<span class="property">class</span>);<span class="comment">//1</span></span><br><span class="line">        service.<span class="title function_">thinking</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>CGLib可以对用有实现接口的类进行代理，也可以为普通类进行代理。<strong>但是，CGLib是通过继承父类并重写父类的方法达到生成代理类的，那么final类和final方法是不能通过CGLib进行代理的</strong></p>
<p>在上述代码中，用一个<code>MethodInterceptor</code>接口的实现类，去实现需要代理的方法的功能。<code>MethodInterceptor</code>接口中只有一个方法<code>intercept</code>，在该方法中调用Proxy类的<code>invokeSuper()</code>方法去调用需要代理的方法。在该方法之前和之后，是需要代理的功能。</p>
<p>其中的<code>getProxy</code>方法，传入一个需要代理的类，在该方法中，用到了Enhancer类，该类是用于增强字节码的一个类，将需要代理的类设置为父类，将实现了<code>MethodInterceptor</code>接口类设置为回调类，最后采用字节码技术创建出一个代理类并返回。</p>
<h2 id="CGLib动态代理和JDK动态代理Spring-AOP中的作用"><a href="#CGLib动态代理和JDK动态代理Spring-AOP中的作用" class="headerlink" title="CGLib动态代理和JDK动态代理Spring AOP中的作用"></a><strong>CGLib动态代理和JDK动态代理Spring AOP中的作用</strong></h2><p>Spring AOP 既采用CGLib动态代理也采用JDK动态代理</p>
<p><strong>如果目标对象实现了接口，默认情况下会采用JDK的动态代理实现AOP</strong></p>
<p><strong>如果目标对象没有实现接口，必须采用CGLib的动态代理实现AOP</strong></p>
<p><strong>CGLib创建的动态代理对象性能比JDK创建的动态代理对象的性能高很多，但是CGLib在创建代理对象时所花费的时间缺比JDK多得多。所以，对于单例的对象，适合使用CGLib创建代理类；反之，适合使用JDK动态代理创建代理类</strong></p>

      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  

      
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="https://cheng-wang123.gitee.io/wang-cheng/2022/03/03/JDBC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/wang-cheng/images/avatar.gif">
      <meta itemprop="name" content="王诚">
      <meta itemprop="description" content="命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="诚の博客">
    </span>
      <header class="post-header">
        <h2 class="post-title" itemprop="name headline">
          
            <a href="/wang-cheng/2022/03/03/JDBC%E5%AD%A6%E4%B9%A0%E7%AC%94%E8%AE%B0/" class="post-title-link" itemprop="url">JDBC学习笔记</a>
        </h2>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>

              <time title="创建时间：2022-03-03 15:08:43" itemprop="dateCreated datePublished" datetime="2022-03-03T15:08:43+08:00">2022-03-03</time>
            </span>
              <span class="post-meta-item">
                <span class="post-meta-item-icon">
                  <i class="far fa-calendar-check"></i>
                </span>
                <span class="post-meta-item-text">更新于</span>
                <time title="修改时间：2022-03-04 12:13:54" itemprop="dateModified" datetime="2022-03-04T12:13:54+08:00">2022-03-04</time>
              </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
          <h1 id="JDBC学习笔记"><a href="#JDBC学习笔记" class="headerlink" title="JDBC学习笔记"></a>JDBC学习笔记</h1><p><code>JDBC</code>即Java DataBase Connectivity，<code>java</code>数据库连接；是<code>Java</code>语言用来规范客户端程序如何来访问数据库的<strong>应用程序接口</strong>，提供了诸如查询、更新数据库中数据的方法。引入<code>JDBC</code>的jar包后，便可使用<code>JDBC</code>。</p>
<h2 id="注册驱动"><a href="#注册驱动" class="headerlink" title="注册驱动"></a>注册驱动</h2><p>1、直接注册：</p>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Driver driver = <span class="keyword">new</span> com.mysql.jdbc.<span class="constructor">Driver()</span>;</span><br><span class="line"><span class="module-access"><span class="module"><span class="identifier">DriverManager</span>.</span></span>register<span class="constructor">Driver(<span class="params">driver</span>)</span>;</span><br></pre></td></tr></table></figure>
<p>只不过这种注册方式已经写死，将来如果更换数据库，就需要去代码中进行更改，非常不利于解耦合。</p>
<p>2、利用配置文件进行注册</p>
<figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">ResourceBundle bundle = <span class="module-access"><span class="module"><span class="identifier">ResourceBundle</span>.</span></span>get<span class="constructor">Bundle(<span class="string">&quot;com.JDBC&quot;</span>)</span>;</span><br><span class="line"><span class="module-access"><span class="module"><span class="identifier">Class</span>.</span></span><span class="keyword">for</span><span class="constructor">Name(<span class="params">bundle</span>.<span class="params">getString</span>(<span class="string">&quot;driver&quot;</span>)</span>);</span><br></pre></td></tr></table></figure>
<p>ResourceBundle这个类的作用主要就是用来读取资源属性文件(properties)，然后根据<code>.proerties</code>文件的名称，获取相应的<code>.properties</code>文件的内容。使用该类必须遵循一定的命名规范，一般文件名必须以<code>.properties</code>为后缀。</p>
<p>配置文件中的内容自定义：</p>
<figure class="highlight ini"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">driver</span>=com.mysql.jdbc.Driver</span><br><span class="line"><span class="attr">url</span>=jdbc:mysql://localhost:<span class="number">3306</span>/数据库名</span><br><span class="line"><span class="attr">username</span>=root</span><br><span class="line"><span class="attr">password</span>=root</span><br></pre></td></tr></table></figure>
<hr>
<h3 id="两种方式的对比"><a href="#两种方式的对比" class="headerlink" title="两种方式的对比"></a><strong>两种方式的对比</strong></h3><p>第一种方式通过 new 一个Driver对象，将对象传递给DriverManager，<code>DriverManager.registerDriver(driver)</code>来进行驱动的注册</p>
<p>第二种方式通过<code>Class.forName(&quot;com.mysql.jdbc.Driver&quot;)</code>类加载机制进行注册。</p>
<p>我们先来看一下<code>DriverManager</code>的<code>registerDriver()</code>方法</p>
<figure class="highlight aspectj"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">synchronized</span> <span class="function"><span class="keyword">void</span> <span class="title">registerDriver</span><span class="params">(java.sql.Driver driver,</span></span></span><br><span class="line"><span class="params"><span class="function">            DriverAction da)</span></span></span><br><span class="line"><span class="function">        <span class="keyword">throws</span> SQLException </span>&#123;</span><br><span class="line"></span><br><span class="line">        <span class="comment">/* Register the driver if it has not already been added to our list */</span></span><br><span class="line">        <span class="keyword">if</span>(driver != <span class="keyword">null</span>) &#123;</span><br><span class="line">            registeredDrivers.addIfAbsent(<span class="keyword">new</span> DriverInfo(driver, da));</span><br><span class="line">        &#125; <span class="keyword">else</span> &#123;</span><br><span class="line">            <span class="comment">// This is for compatibility with the original DriverManager</span></span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> NullPointerException();</span><br><span class="line">        &#125;</span><br><span class="line"></span><br><span class="line">        println(<span class="string">&quot;registerDriver: &quot;</span> + driver);</span><br><span class="line"></span><br><span class="line">    &#125;</span><br></pre></td></tr></table></figure>
<p>在该方法中，会将Driver对象封装成一个DriverInfo对象。</p>
<p>再来看一下Driver类</p>
<figure class="highlight scala"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line">public <span class="class"><span class="keyword">class</span> <span class="title">Driver</span> <span class="keyword">extends</span> <span class="title">NonRegisteringDriver</span> <span class="title">implements</span> <span class="title">java</span>.<span class="title">sql</span>.<span class="title">Driver</span> </span>&#123;  </span><br><span class="line">    <span class="comment">// ~ Static fields/initializers  </span></span><br><span class="line">    <span class="comment">// ---------------------------------------------  </span></span><br><span class="line">  </span><br><span class="line">    <span class="comment">//  </span></span><br><span class="line">    <span class="comment">// Register ourselves with the DriverManager  </span></span><br><span class="line">    <span class="comment">//  </span></span><br><span class="line">    static &#123;  </span><br><span class="line">        <span class="keyword">try</span> &#123;  </span><br><span class="line">            java.sql.<span class="type">DriverManager</span>.registerDriver(<span class="keyword">new</span> <span class="type">Driver</span>());  </span><br><span class="line">        &#125; <span class="keyword">catch</span> (<span class="type">SQLException</span> <span class="type">E</span>) &#123;  </span><br><span class="line">            <span class="keyword">throw</span> <span class="keyword">new</span> <span class="type">RuntimeException</span>(<span class="string">&quot;Can&#x27;t register driver!&quot;</span>);  </span><br><span class="line">        &#125;  </span><br><span class="line">    &#125;  </span><br></pre></td></tr></table></figure>
<p>在该类中有一段静态代码块，是向DriverManager注册一个Driver实例。</p>
<p>再来看上述两种注册方式：</p>
<p>第一种方式是采用DriverManager进行注册，在注册是会先实例化一个Driver对象，而通过分析Driver源码可知，在实例化对象时就已经向DriverManager注册了驱动。而第二种方式通过类加载机制，只对Driver实例化了一次，便进行了驱动的注册。</p>
<p>通过分析可知，当我们使用第一种方式进行注册时，静态代码块已经执行了，相当于是实例化了两个Driver对象。并且，使用第一种方式产生了一种对MySQL的依赖，而类加载机制的方式使得我们完全可以在运行时再动态的改变我们想要使用的数据库。</p>
<h2 id="获取连接"><a href="#获取连接" class="headerlink" title="获取连接"></a>获取连接</h2><figure class="highlight reasonml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">String url = bundle.get<span class="constructor">String(<span class="string">&quot;url&quot;</span>)</span>;</span><br><span class="line">String username = bundle.get<span class="constructor">String(<span class="string">&quot;username&quot;</span>)</span>;</span><br><span class="line">String password = bundle.get<span class="constructor">String(<span class="string">&quot;password&quot;</span>)</span>;</span><br><span class="line">Connection conn = <span class="module-access"><span class="module"><span class="identifier">DriverManager</span>.</span></span>get<span class="constructor">Connection(<span class="params">url</span>,<span class="params">username</span>,<span class="params">password</span>)</span>;</span><br></pre></td></tr></table></figure>
<p>通过getConnection()方法获取数据库的连接。</p>
<h2 id="获取数据库操作对象"><a href="#获取数据库操作对象" class="headerlink" title="获取数据库操作对象"></a>获取数据库操作对象</h2><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">Statement statement <span class="operator">=</span> conn.createStatement()<span class="comment">;</span></span><br></pre></td></tr></table></figure>

<p>使用PrepareStatement</p>
<figure class="highlight n1ql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">String sql = &quot;<span class="keyword">select</span> * <span class="keyword">from</span> <span class="keyword">user</span> <span class="keyword">where</span> name = ? <span class="string">&quot;;</span></span><br><span class="line"><span class="string">PrepareStatement ps = connection.prepareStatement(sql);</span></span><br><span class="line"><span class="string">ps.setString(1,&quot;</span><span class="number">5</span><span class="string">&quot;);</span></span><br></pre></td></tr></table></figure>

<h3 id="Statement和PrepareStatement的区别"><a href="#Statement和PrepareStatement的区别" class="headerlink" title="Statement和PrepareStatement的区别"></a><strong>Statement和PrepareStatement的区别</strong></h3><p>Statement用于执行静态SQL语句，在执行时，必须事先指定一个准备好的SQL语句<br>PrepareStatement是预编译的SQL语句对象，采用了Cache机制，预先编译的语句会先放到Cache中。由于使用了预编译，当执行相同的SQL语句时，可以直接从Cache中取出来，大大提高了批处理的效率，执行速度提高了成百上千倍。</p>
<h2 id="执行SQL语句"><a href="#执行SQL语句" class="headerlink" title="执行SQL语句"></a>执行SQL语句</h2><figure class="highlight abnf"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ResultSet resultSet <span class="operator">=</span> ps.executeQuery()<span class="comment">;</span></span><br></pre></td></tr></table></figure>
<p>结果集ResultSet是数据中查询结果返回的一种对象，可以说结果集是一个存储查询结果的对象，但是结果集并不仅仅具有存储的功能，他同时还具有操纵数据的功能，可能完成对数据的更新等。</p>
<h2 id="关闭连接"><a href="#关闭连接" class="headerlink" title="关闭连接"></a>关闭连接</h2><p>执行完SQL语句是要关闭连接进行资源释放的。而且连接的关闭也是有顺序的，必须要先关闭ResultSet，然后关闭PreparedStatement，最后关闭Connection。</p>
<figure class="highlight php"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (resultSet != <span class="literal">null</span>)&#123;</span><br><span class="line">        resultSet.<span class="title function_ invoke__">close</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;<span class="keyword">catch</span> (<span class="built_in">Exception</span> e)&#123;</span><br><span class="line">    e.<span class="title function_ invoke__">printStackTrace</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (ps != <span class="literal">null</span>)&#123;</span><br><span class="line">        ps.<span class="title function_ invoke__">close</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;<span class="keyword">catch</span> (<span class="built_in">Exception</span> e)&#123;</span><br><span class="line">    e.<span class="title function_ invoke__">printStackTrace</span>();</span><br><span class="line">&#125;</span><br><span class="line"><span class="keyword">try</span> &#123;</span><br><span class="line">    <span class="keyword">if</span> (connection != <span class="literal">null</span>)&#123;</span><br><span class="line">        connection.<span class="title function_ invoke__">close</span>();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;<span class="keyword">catch</span> (<span class="built_in">Exception</span> e)&#123;</span><br><span class="line">    e.<span class="title function_ invoke__">printStackTrace</span>();</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>




      
    </div>

    
    
    
      <footer class="post-footer">
        <div class="post-eof"></div>
      </footer>
  </article>
  
  
  


  
  <nav class="pagination">
    <a class="extend prev" rel="prev" href="/wang-cheng/page/3/"><i class="fa fa-angle-left" aria-label="上一页"></i></a><a class="page-number" href="/wang-cheng/">1</a><span class="space">&hellip;</span><a class="page-number" href="/wang-cheng/page/3/">3</a><span class="page-number current">4</span>
  </nav>



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
  <p class="site-author-name" itemprop="name">王诚</p>
  <div class="site-description" itemprop="description">命运对勇士低语，你无法抵御风暴；勇士低声回应，我就是风暴</div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/wang-cheng/archives/">
        
          <span class="site-state-item-count">32</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/wang-cheng/tags/">
          
        <span class="site-state-item-count">12</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>



      </div>

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2022</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">王诚</span>
</div>
  <div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>

        
<div class="busuanzi-count">
  <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>
    <span class="post-meta-item" id="busuanzi_container_site_uv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-user"></i>
      </span>
      <span class="site-uv" title="总访客量">
        <span id="busuanzi_value_site_uv"></span>
      </span>
    </span>
    <span class="post-meta-divider">|</span>
    <span class="post-meta-item" id="busuanzi_container_site_pv" style="display: none;">
      <span class="post-meta-item-icon">
        <i class="fa fa-eye"></i>
      </span>
      <span class="site-pv" title="总访问量">
        <span id="busuanzi_value_site_pv"></span>
      </span>
    </span>
</div>








      </div>
    </footer>
  </div>

  
  <script src="/wang-cheng/lib/anime.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.min.js"></script>
  <script src="/wang-cheng/lib/velocity/velocity.ui.min.js"></script>

<script src="/wang-cheng/js/utils.js"></script>

<script src="/wang-cheng/js/motion.js"></script>


<script src="/wang-cheng/js/schemes/pisces.js"></script>


<script src="/wang-cheng/js/next-boot.js"></script>




  















  

  

  

</body>
</html>
